<?php
namespace app\common\service;

use plug\SUtil;
use think\exception\HttpException;
use think\facade\Config;
use plug\SHttp;
use think\cache\driver\Redis;

class Wechat
{
    private $wxMerchantApiCertificate = __DIR__ . "/serial/apiclient_cert.pem";       //商户证书
    private $wxMerchantApiPrivateKey = __DIR__ . "/cert/apiclient_key.pem";         //商户私钥
	/**
	 * 获取access_token
	 * @return void
	 * @throws \think\Exception
	 */
	public static function GetAccessToken($type){
		$wxconf = config::pull('weixin');
		$redisName = $wxconf['AppID'].'AuthorizeTokenInfo-'.$type;
		$Redis = new Redis();

		//查询缓存AccessToken是否已过期
		$AuthorizeTokenInfo = json_decode($Redis->get($redisName),true);
		if($AuthorizeTokenInfo && @$AuthorizeTokenInfo['access_token_exp'] > time()){
			return $AuthorizeTokenInfo['access_token'];
		}

		$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$wxconf['AppID']."&secret=".$wxconf['AppSecret'];
		$return = SHttp::http_curl($url);
		$data = json_decode($return['str'],true);
		if(!$data || !empty($data['errcode']) || !empty($data['errmsg'])){
			throw new \think\Exception($data['errmsg'], $data['errcode']);
		}

		//存redis里面
		$data['access_token_exp'] = calculate([time(),7000],'+',0);
		$Redis->set($redisName,json_encode($data));
		return $data['access_token'];
	}

    /**
     * 获取通用access_token
     * @return void
     * @throws \think\Exception
     */
    public static function GetNormalAccessToken($wxconf){
        $redisName = $wxconf['AppID'].'AuthorizeTokenInfo';
        $Redis = new Redis();

        //查询缓存AccessToken是否已过期
        $AuthorizeTokenInfo = json_decode($Redis->get($redisName),true);
        if($AuthorizeTokenInfo && @$AuthorizeTokenInfo['access_token_exp'] > time()){
            return $AuthorizeTokenInfo['access_token'];
        }

        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$wxconf['AppID']."&secret=".$wxconf['AppSecret'];
        $return = SHttp::http_curl($url);
        $data = json_decode($return['str'],true);
        if(!$data || !empty($data['errcode']) || !empty($data['errmsg'])){
            throw new \think\Exception($data['errmsg'], $data['errcode']);
        }

        //存redis里面
        $data['access_token_exp'] = calculate([time(),7000],'+',0);
        $Redis->set($redisName,json_encode($data));
        return $data['access_token'];
    }

    /**
     * @title 获取用户小程序码
     * @param string $page 默认是主页，页面 page，例如 pages/index/index，根路径前不要填加 /，不能携带参数（参数请放在 scene 字段里），如果不填写这个字段，默认跳主页面
     * @param int $width 默认430，二维码的宽度，单位 px，最小 280px，最大 1280px
     * @param bool $auto_color 自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调，默认 false
     * @param string $line_color 默认是{"r":0,"g":0,"b":0} 。auto_color 为 false 时生效，使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示
     * @param bool $is_hyaline 默认是false，是否需要透明底色，为 true 时，生成透明底色的小程序
     * @return bool
     */
    public static function getwxacodeunlimit($config,$name,$arr,$path = 'QRcode/',$page='pages/index/index',$width=430,$auto_color=false,$line_color='{"r":0,"g":0,"b":0}',$is_hyaline=false)
    {
        //获取access_token
        $access_token = Wechat::GetNormalAccessToken($config);
        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=".$access_token;
        $data = [
            'scene' => http_build_query($arr),
            'page' => $page,
            'width' => $width,
            'auto_color' => $auto_color,
            'line_color' => json_decode($line_color),
            'is_hyaline' => $is_hyaline,
        ];

        $return = SHttp::http_curl($url,json_encode($data),[],'post');
        $data = json_decode($return['str'],true);
        if ($data['errcode']) {
            throw new \think\Exception($data['errmsg'].',错误码：'. $data['errcode']);
        }

        $dirname = 'uploads/'.$path;
        $query['path'] = $dirname;
        if (!file_exists($query['path'])) {
            if (!mkdir($query['path'], 0777, true)) {
                throw new \think\Exception('创建文件夹失败', -1);
            }
        }

        $query['name'] = $name.'.jpg';
        $fullName = $query['path'] . $query['name'];
        if (!file_put_contents($fullName,$return)) {
            throw new \think\Exception('上传错误', -1);
        }

        return $fullName;
    }

	/**
	 * 获取公众号授权链接
	 * @return string[]
	 */
	public static function GetAuthorizeUrl($redirect_uri){
		$wxconf = config::pull('weixin');
		$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$wxconf['AppID']."&redirect_uri=".$redirect_uri."&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
		return ['url'=>$url];
	}

	/**
	 * 通过 code 换取网页授权access_token和openid
	 * 这里通过 code 换取的是一个特殊的网页授权access_token,与基础支持中的access_token（该access_token用于调用其他接口）不同
	 * @param $code
	 * @return false|mixed
	 */
	public static function AuthorizeInfo($code){
		$wxconf = config::pull('weixin');
		$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$wxconf['AppID']."&secret=".$wxconf['AppSecret']."&code=".$code."&grant_type=authorization_code";
		$return = SHttp::http_curl($url);
		$data = json_decode($return['str'],true);
		if(!empty($data['errcode']) || !empty($data['errmsg'])){
			throw new HttpException(-2,$data['errmsg'].$data['errcode']);
		}
		return $data;
	}

	/**
	 * 获取用户基本信息（包括UnionID机制）
	 * @param $access_token
	 * @param $openid
	 * @return false|mixed
	 */
	public static function userinfo($access_token,$openid){
		$url = "https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
		$return = SHttp::http_curl($url);
		$data = json_decode($return['str'],true);
		if(!empty($data['errcode']) || !empty($data['errmsg'])){
			throw new HttpException(-2,$data['errmsg'].$data['errcode']);
		}
		return $data;
	}

	/**
	 * 获取用户基本信息（包括UnionID机制）
	 * @param $openid
	 * @return false|mixed
	 */
	public static function getuserinfo($openid){
        //获取access_token
        $access_token = Wechat::GetAccessToken('userinfo');
		$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
		$return = SHttp::http_curl($url);
		$data = json_decode($return['str'],true);
		if(!empty($data['errcode']) || !empty($data['errmsg'])){
			throw new HttpException(-2,$data['errmsg'].$data['errcode']);
		}
		return $data;
	}

	/**
	 * 发送用户消息
	 * @param $data
	 * @return false|mixed
	 */
	public static function sendusermsg($data){
	    $data = json_encode($data);
        //获取access_token
        $access_token = Wechat::GetAccessToken('sendusermsg');
		$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$access_token;
		$return = SHttp::http_curl($url,$data,'','post');
		$data = json_decode($return['str'],true);
//		if(!empty($data['errcode']) || !empty($data['errmsg'])){
		if($data['errcode'] != 0){
			throw new HttpException(-2,$data['errmsg'].$data['errcode']);
		}
		return $data;
	}

	/**
	 * 公众号自定义菜单栏
	 * @param $data
	 * @return false|mixed
	 */
	public static function createmenu($data){
	    $data = json_encode($data,JSON_UNESCAPED_UNICODE);
        //获取access_token
        $access_token = Wechat::GetAccessToken('custommenu');
		$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$access_token;
		$return = SHttp::http_curl($url,$data,'','post');
		$data = json_decode($return['str'],true);
//		if(!empty($data['errcode']) || !empty($data['errmsg'])){
		if($data['errcode'] != 0){
			throw new HttpException(-2,$data['errmsg'].$data['errcode']);
		}
		return $data;
	}

    /**
     * @title 小程序订阅消息推送
     * @param int $touser 接受推送用户id
     * @param string $page 默认是主页，页面 page，例如 pages/index/index，根路径前不要填加 /，支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
     * @param string $template_id 所需下发的订阅模板id
     * @param string $data 模板内容，格式形如 { "key1": { "value": any }, "key2": { "value": any } }的object
     * @param string $miniprogram_state 跳转小程序类型：developer为开发版；trial为体验版；formal为正式版；默认为正式版
     * @param string $lang 进入小程序查看”的语言类型，支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文)，默认为zh_CN
     * @return bool
     */
    public static function messagepush($config,$touser,$template_id,$page = '',$post_data,$miniprogram_state = 'formal',$lang = 'zh_CN')
    {
//        var_dump(json_encode($post_data,true));die;
        //获取access_token
        $access_token = Wechat::GetMessageAccessToken($config,'applet_msg');
//        var_dump($access_token);
        $url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=".$access_token;
        $data = [
            'access_token' => $access_token,
            'template_id' => $template_id, // 模板id
            'page' => $page,
            'touser' => $touser,
            'data' => $post_data,
            'miniprogram_state' => $miniprogram_state,
            'lang' => $lang,
        ];

        $return = SHttp::http_curl($url,json_encode($data),[],'post');
        $data = json_decode($return['str'],true);
        if ($data['errcode']) {
            throw new \think\Exception($data['errmsg'].',错误码：'. $data['errcode']);
        }

        return $data;
    }

    /**
     * @title 公众号消息推送
     * @param array $config 公众号配置信息
     * @param int $touser 接受推送用户id
     * @param string $template_id 所需下发的订阅模板id
     * @param string $jump_url 模板跳转链接（海外帐号没有跳转能力），例如 https://www.baidu.com。该字段不填则模板无跳转
     * @param string $applet_app_id 所需跳转到的小程序appid（该小程序appid必须与发模板消息的公众号是绑定关联关系，暂不支持小游戏）
     * @param string $pagepath 默认是主页，页面 page，例如 pages/index/index，根路径前不要填加 /，支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
     * @param string $data 模板内容，格式形如 { "key1": { "value": any }, "key2": { "value": any } }的object
     */
    public static function wxmessagepush($config,$touser,$template_id,$jump_url = '',$applet_app_id = '',$pagepath = '',$post_data,$client_msg_id = '')
    {
//        var_dump(json_encode($post_data,true));die;
        //获取access_token
        $access_token = Wechat::GetMessageAccessToken($config,'weixin_msg');
//        var_dump($access_token);
        $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=".$access_token;
        $data = [
            'touser' => $touser,
            'template_id' => $template_id, // 模板id
            'url' => $jump_url,
            'data' => $post_data,
            'client_msg_id' => $client_msg_id,
        ];
        if(!empty($applet_app_id)){
            $data['miniprogram'] = [
                'appid' => $applet_app_id,
                'pagepath' => $pagepath
            ];
        }

        $return = SHttp::http_curl($url,json_encode($data,JSON_UNESCAPED_UNICODE),[],'post');
        $data = json_decode($return['str'],true);
        if ($data['errcode']) {
            throw new \think\Exception($data['errmsg'].',错误码：'. $data['errcode']);
        }

        return $data;
    }

    /**
     * 获取消息access_token
     * @return void
     * @throws \think\Exception
     * @param string $type 发送消息端：weixin_msg-微信端，applet_msg-小程序端
     */
    public static function GetMessageAccessToken($config,$type='weixin_msg'){
        $redisName = $config['AppID'].'AuthorizeTokenInfo'.'-'.$type;
        $Redis = new Redis();

        //查询缓存AccessToken是否已过期
        $AuthorizeTokenInfo = json_decode($Redis->get($redisName),true);
        if($AuthorizeTokenInfo && @$AuthorizeTokenInfo['access_token_exp'] > time()){
            return $AuthorizeTokenInfo['access_token'];
        }
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$config['AppID']."&secret=".$config['AppSecret'];
        $return = SHttp::http_curl($url);
        $data = json_decode($return['str'],true);
        if(!$data || !empty($data['errcode']) || !empty($data['errmsg'])){
            throw new \think\Exception($data['errmsg'], $data['errcode']);
        }

        //存redis里面
        $data['access_token_exp'] = calculate([time(),7000],'+',0);
        $Redis->set($redisName,json_encode($data));
        return $data['access_token'];
    }

	/**
	 * 生成签名
	 * @return 签名，本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
	 */
	public static function MakeSign($data)
	{
		//签名步骤一：按字典序排序参数
		ksort($data);
		//格式化参数格式化成url参数
		$string = ToUrlParams();
		//签名步骤二：在string后加入KEY
		$string = $string . "&key=".config::pull('weixin')['AppSecret'];
		//签名步骤三：MD5加密
		$string = md5($string);
		//签名步骤四：所有字符转为大写
		$result = strtoupper($string);
		return $result;
	}

	/**
	 * 获取授权页ticket
	 */
	public static function JsapiTicket(){
		$wxconf = config::pull('weixin');
		$redisName = $wxconf['AppID'].'AuthorizeTicketInfo';
		$Redis = new Redis();

		//查询缓存ticket是否已过期
		$AuthorizeTicketInfo = json_decode($Redis->get($redisName),true);
		if($AuthorizeTicketInfo && @$AuthorizeTicketInfo['ticket_exp'] > time()){
			return $AuthorizeTicketInfo['ticket'];
		}

		//获取access_token
		$access_token = Wechat::GetAccessToken('getticket');
		$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$access_token;
		$return = SHttp::http_curl($url);
		$data = json_decode($return['str'],true);
		if(!$data || empty($data['ticket']) || empty($data['expires_in'])){
			throw new \think\Exception($data['errmsg'], $data['errcode']);
		}

		//存redis里面
		$data['ticket_exp'] = calculate([time(),7000],'+',0);
		$Redis->set($redisName,json_encode($data));
		return $data['ticket'];
	}

    /**
     * 订单退款
     * @return void
     * @throws \think\Exception
     */
    public static function OrderRefund($post_data){
        $url = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
//        $certificatePath = '/data/wwwroot/xiaozaopai/service/serial/apiclient_cert.pem';
        $certificateKeyPath = '/data/wwwroot/xiaozaopai/service/serial/apiclient_key.pem';
//        print_r(file_get_contents($certificateKeyPath));
//        var_dump(openssl_get_privatekey(file_get_contents($certificateKeyPath)));die;
//        var_dump(openssl_get_privatekey("-----BEGIN PRIVATE KEY----- MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDYxt0XGEZFwGbX 1pAScn14KXvlvJhDlU/7lGksHplTVHM9ICu72lAZ2zFjT6uFFU0qeB3U2Win56Is swF1eox2nQbKbdP2KE/QH60353AdFacv5qhSz/VZxpYQPMLLVctnqff0DsekGh2O C20nsn/iVbpNCp965u/ThehccUHly/mtw8TUPfZFCV0fKc8Mvt7741cBkThqK6Ze SlFGfAIl4icBm8Gods085wZZ0XE9ZopOLCrpzQ1+mJPl9NXBiHlWHOHBrz/uit02 cN2oqre1OvMUX7BFc8ao4iURKJZyP09oRmL+kQnNdltRcdB25kfcjygLaJagjzGB 6IDd8D+vAgMBAAECggEBAMkl3klr0OkwWz20bwNvEVXKyJioo3Eyv4DmeaDi08sq 9bOmgm5RaTpU1kMczj8zQONDigrTofULTsTDZXspN+VoV8DGoIQta8HnYsgZDUMv sG8WTOJq7XNcfiqa9vXOqmuKn/XrMPzo7ru7hpHrZBcVDUYnsUxNtgREoRQGU+tx 4GM++kTvNtVUig9wJukojSFq1EOnctl+y5Y67vIlldd87K2D0H6cjCLE6nNNpI2/ ml2Hfn+Be8eIQqv19s7Z4eVeGkxXHOBHSFr8IAIPczuFGRxTQYb+o5L156yiCqX3 PY6WzuLumsqinnO8r+Czt9lBKZomNGcZDSlOoCxhAkECgYEA+RKp+aIcqaqdyrUy PvRU0JlrbQgokY1gLKHoymI2Oqk4iP3o7m346MrB57Nj2o45S9VT0HN+PHG7Ajl8 cik0LeTqTSbKKm1emswL7XlC45wpS/WJgnlOfkkLjk3RG+49DrYmqRAh/ussx2dc lKLIrF6Ujb/ZfQuqGgZsOFTzQskCgYEA3s5CeEgzEKvzt07L+WZLwOr/V1k5AR1H yqzyLxb4zykyqtonunLL2CgMyFVmQ6vxalUSXOQhZ8lov8cBaVEZK6upbhWgdfn9 kBVW7r6jd03BkJ4rgpI8gmkxwoQwZhcWbXZg3oxkYFXlhGVdAJEqlnhVa0i/ap8G lT3FsbbecrcCgYEA7m9xjGomaj3MxErliOK5duAHuN7Ah2YBlXiBs4yFQW7RkkMP g4B/ccr4CWjvxD+2lePoUnrdc9ukHKMPgPH046JqseTaT/dXQ3TmTjVxVRcfaXnq Y57hB3/Bsj7IWaadiMHTDLFG+hQET/eg5yFWXbxFFdV8zHooIrXXT63zGhECgYEA op71UQmRjAeVeSPgKQaLICHlgQG0Y6XVco7MraYcsEennaBhAusq8Xg57Da4z4e+ SxgQsRApebE97Uv5Mb9pmcBPh/PtDG8MrY+FxfgLI9bzAvUPWNwXoi/Zi9oj4T/U tMyEY6sg0FehkALT4MgTx4PJBOcyH0Y27dMKam3I6v0CgYEArnQEdEag0kPb1LOF 2CkbaSaZqzP7IdgPEtWEcnpevqQoWQ1NPuomlMEoc8D9CgjM2ORacNFXZVpYxgL1 SXoJERUWI40Wo26Yb0DA7USvrSWV2rs2Oa/IVME1DgRduWTIebIaqeVGt+2+LYNZ 45pvlVZExgZjfsWrbyfhJIQUwug= -----END PRIVATE KEY-----"));die;
//        // 证书文件路径
//        $certificateData = file_get_contents($certificatePath);
//        $certificateInfo = openssl_x509_parse($certificateData);
//        if ($certificateInfo) {
//            // 获取并输出序列号
//             $serialNumber = $certificateInfo['serialNumber'];
//        } else {
//            throw new \think\Exception("Failed to parse certificate.");
//        }
        $wxconf = config::pull('weixin_applet');
        $serial_no = '45747E6CE0A37D9AEBFC5F121DEF4A6C912F0BD6';
//        var_dump($post_data);
//        var_dump($serial_no);die;
        $Authorization = Wechat::RequestSign("POST", $url, $post_data, $wxconf['MchId'], $certificateKeyPath, $serial_no);
//        var_dump($Authorization);
        $header = [
            'Accept:application/json',
            'Content-Type:application/json',
            "User-Agent:{$_SERVER['HTTP_USER_AGENT']}",
            "Authorization:WECHATPAY2-SHA256-RSA2048 {$Authorization}",
        ];
//        var_dump($header);
        $return = SHttp::http_curl($url,$post_data,$header,'post');
//        var_dump($return);die;
        $data = json_decode($return['str'],true);
//        var_dump($data);die;
        if(!$data || $return['status'] != '200'){
            throw new \think\Exception($data['code'].": ".$data['message']);
        }

        return $data;
    }

    /**
     * 生成签名
     * @param string $method 请求方法 POST 或者GET
     * @param string $url 请求URL
     * @param string $request 请求中的请求报文主体
     * @param $wxMerchantId商户号
     * @param $certKey商户私钥
     * @param $wxApiSerialNo商户API证书序列号
     * @return string
     */
    public static function RequestSign($method = "POST", $url = "", $request = "", $wxMerchantId, $certKey, $wxApiSerialNo)
    {
        #截取获取当前请求地址【去除域名】
        $url_parts = parse_url($url);
        $path = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        #获取当前时间戳
        $timeStamp = time();
        #生成一个随机字符串
        $nonceStr = Wechat::getNonceStr();
        #构造签名串
        $requestSign = sprintf("%s\n%s\n%s\n%s\n%s\n", $method, $path, $timeStamp, $nonceStr, $request);
//        var_dump($requestSign);
//        var_dump(strlen($requestSign));
        #计算计算签名值
        $sign = Wechat::calculateSignatureValue($requestSign, $certKey);
        #设置HTTP头获取Authorization
        $token = Wechat::createToken($wxMerchantId, $nonceStr, $timeStamp, $wxApiSerialNo, $sign);
        #返回
        return $token;
    }

    /**
     * 计算签名值
     * @param $requestSign
     * @param $certKey
     * @return string
     * 使用商户私钥对待签名串进行SHA256 with RSA签名，并对签名结果进行Base64编码得到签名值
     */
    public static function calculateSignatureValue($requestSign, $certKey)
    {
        $certKey = file_get_contents($certKey);
        openssl_sign($requestSign, $raw_sign, $certKey, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        return $sign;
    }
    /**
     * 获取token
     * @param $merchant_id
     * @param $nonce
     * @param $timestamp
     * @param $serial_no
     * @param $sign
     * @return string
     */
    public static function createToken($merchant_id, $nonce, $timestamp, $serial_no, $sign)
    {
        $schema = 'WECHATPAY2-SHA256-RSA2048';
        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $merchant_id, $nonce, $timestamp, $serial_no, $sign);
        return $token;
    }

    /**
     * 产生随机字符串，不长于32位
     * @param int $length
     * @return string
     */
    public static function getNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * 上传永久图片素材
     */
    public static function upload_wx_perpetual_image($imageinfo,$type = 'image'){
        //获取access_token
        $access_token = Wechat::GetAccessToken('upload_image');
//        var_dump($access_token);
        $url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={$access_token}&type={$type}";
//        $path = realpath($imageinfo['filename']);
        $data = [
            'access_token' => $access_token,
            'type' => $type,
            'media' => '@'.$imageinfo['filename'],
        ];
        var_dump($data);
        $return = SHttp::http_curl($url,json_encode($data),[],'post');
        $data = json_decode($return['str'],true);
        if ($data['errcode']) {
            throw new \think\Exception($data['errmsg'].',错误码：'. $data['errcode']);
        }

        return $data;
    }

    /**
     * 小程序获取openid
     * 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。更多使用方法详见小程序登录。
     * @param $code
     * @return void
     * @throws \think\Exception
     */
    public static function jscode2session($code)
    {
        $wxconf = config::pull('weixin_applet');
        $url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $wxconf['AppID'] . "&secret=" . $wxconf['AppSecret'] . "&js_code=" . $code . "&grant_type=authorization_code";
        $return = SHttp::http_curl($url);
        $data = json_decode($return['str'],true);

        if(!$data || empty($data['session_key']) || empty($data['openid'])){
            throw new \think\Exception($data['errmsg'], $data['errcode']);
        }
        return $data;
    }

    /**
     * 检验数据的真实性，并且获取解密后的明文.https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
     * @param $session_key string 会话密钥
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @param $data string 解密后的原文
     *
     * @return int 成功0，失败返回对应的错误码
     */
    public static function decryptData($session_key,$encryptedData, $iv, &$data )
    {
        $wxconf = config::pull('weixin_applet');
        if (strlen($session_key) != 24) {
            return -41001;
        }
        $aesKey=base64_decode($session_key);


        if (strlen($iv) != 24) {
            return -41002;
        }
        $aesIV=base64_decode($iv);

        $aesCipher=base64_decode($encryptedData);

        $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

        $dataObj=json_decode( $result );
        if( $dataObj  == NULL )
        {
            return -410031;
        }
        if( $dataObj->watermark->appid != $wxconf['AppID'] )
        {
            return -410032;
        }
        $data = $result;
        return 0;
    }

    /**
     * 查询错误信息rid
     * @return void
     * @throws \think\Exception
     * @param string $type 发送消息端：weixin_msg-微信端，applet_msg-小程序端
     */
    public static function checkerror($config,$type='weixin_msg',$rid){
        $access_token = Wechat::GetMessageAccessToken($config,$type);
//        var_dump($access_token);
        $url = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get?access_token=".$access_token;
        $data = [
            'rid' => $rid,
        ];

        $return = SHttp::http_curl($url,json_encode($data,JSON_UNESCAPED_UNICODE),[],'post');
        $data = json_decode($return['str'],true);
        if ($data['errcode']) {
            throw new \think\Exception($data['errmsg'].',错误码：'. $data['errcode']);
        }

        return $data;
    }

//    public static function doRefund($totalFee, $refundFee, $refundNo, $wxOrderNo='',$orderNo='')
//    {
//        $config = array(
//            'mch_id' => '1677625696',
//            'appid' => 'wx2b8bd3292d49e718',
//            'key' => '85312e823e4a4508cbc8a8e917a4d021',
//        );
//        $unified = array(
//            'appid' => $config['appid'],
//            'mch_id' => $config['mch_id'],
//            'nonce_str' => self::createNonceStr(),
//            'total_fee' => intval($totalFee * 100),    //订单金额  单位 转为分
//            'refund_fee' => intval($refundFee * 100),    //退款金额 单位 转为分
//            'sign_type' => 'MD5',      //签名类型 支持HMAC-SHA256和MD5，默认为MD5
//            'transaction_id'=>$wxOrderNo,        //微信订单号
//            'out_trade_no'=>$orderNo,    //商户订单号
//            'out_refund_no'=>$refundNo,    //商户退款单号
//            'refund_desc'=>'商品已售完',   //退款原因（选填）
//        );
//        $unified['sign'] = self::getSign($unified, $config['key']);
//        $responseXml = Wechat::curlPost('https://api.mch.weixin.qq.com/secapi/pay/refund', self::arrayToXml($unified));
//        var_dump($responseXml);die;
//        $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
//        if ($unifiedOrder === false) {
//            die('parse xml error');
//        }
//        if ($unifiedOrder->return_code != 'SUCCESS') {
//            die($unifiedOrder->return_msg);
//        }
//        if ($unifiedOrder->result_code != 'SUCCESS') {
//            die($unifiedOrder->err_code);
//        }
//        return true;
//    }
//    public static function curlGet($url = '', $options = array())
//    {
//        $ch = curl_init($url);
//        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
//        if (!empty($options)) {
//            curl_setopt_array($ch, $options);
//        }
//        //https请求 不验证证书和host
//        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
//        $data = curl_exec($ch);
//        curl_close($ch);
//        return $data;
//    }
//    public static function curlPost($url = '', $postData = '', $options = array())
//    {
//        if (is_array($postData)) {
//            $postData = http_build_query($postData);
//        }
//        $ch = curl_init();
//        curl_setopt($ch, CURLOPT_URL, $url);
//        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//        curl_setopt($ch, CURLOPT_POST, 1);
//        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
//        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
//        if (!empty($options)) {
//            curl_setopt_array($ch, $options);
//        }
//        //https请求 不验证证书和host
//        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
//        //第一种方法，cert 与 key 分别属于两个.pem文件
//        //默认格式为PEM，可以注释
//        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
//        curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/cert/apiclient_cert.pem');
//        //默认格式为PEM，可以注释
//        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
//        curl_setopt($ch,CURLOPT_SSLKEY,getcwd().'/cert/apiclient_key.pem');
//        //第二种方式，两个文件合成一个.pem文件
////    curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
//        $data = curl_exec($ch);
//        curl_close($ch);
//        return $data;
//    }
//    public static function createNonceStr($length = 16)
//    {
//        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
//        $str = '';
//        for ($i = 0; $i < $length; $i++) {
//            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
//        }
//        return $str;
//    }
//    public static function arrayToXml($arr)
//    {
//        $xml = "<xml>";
//        foreach ($arr as $key => $val) {
//            if (is_numeric($val)) {
//                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
//            } else
//                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
//        }
//        $xml .= "</xml>";
//        return $xml;
//    }
//    public static function getSign($params, $key)
//    {
//        ksort($params, SORT_STRING);
//        $unSignParaString = self::formatQueryParaMap($params, false);
//        $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
//        return $signStr;
//    }
//    protected static function formatQueryParaMap($paraMap, $urlEncode = false)
//    {
//        $buff = "";
//        ksort($paraMap);
//        foreach ($paraMap as $k => $v) {
//            if (null != $v && "null" != $v) {
//                if ($urlEncode) {
//                    $v = urlencode($v);
//                }
//                $buff .= $k . "=" . $v . "&";
//            }
//        }
//        $reqPar = '';
//        if (strlen($buff) > 0) {
//            $reqPar = substr($buff, 0, strlen($buff) - 1);
//        }
//        return $reqPar;
//    }
}
